﻿using System;
using System.ComponentModel;
using System.Data;
using org.se.fs.presenter.Library;

namespace org.se.fs.presenter.Task.Template
{
    public abstract class Crud
    {
        protected bool IsSuccess;
        protected bool IsError;

        #region Event Members
        public event FormEvent.FormEventHandler OnFetch;
        public event FormEvent.FormEventHandler OnFetchLists;
        public event FormEvent.FormEventHandler OnInsert;
        public event FormEvent.FormEventHandler OnUpdate;
        public event FormEvent.FormEventHandler OnDelete;
        public event FormEvent.FormEventHandler OnToggle;
        public event FormEvent.FormEventHandler OnError;
        public event FormEvent.FormEventHandler OnGetCount;
        public event FormEvent.FormEventHandler OnGetActive;
        public event FormEvent.FormEventHandler OnGetById;
        public event FormEvent.FormEventHandler OnGetId;

        protected void TriggerFetch(FormEvent e)
        {
            if (OnFetch != null)
                OnFetch(this, e);
        }

        protected void TriggerFetchLists(FormEvent e)
        {
            if (OnFetchLists != null)
                OnFetchLists(this, e);
        }

        protected void TriggerInsert(FormEvent e)
        {
            if (OnInsert != null)
                OnInsert(this, e);
        }

        protected void TriggerUpdate(FormEvent e)
        {
            if (OnUpdate != null)
                OnUpdate(this, e);
        }

        protected void TriggerDelete(FormEvent e)
        {
            if (OnDelete != null)
                OnDelete(this, e);
        }

        protected void TriggerToggle(FormEvent e)
        {
            if (OnToggle != null)
                OnToggle(this, e);
        }

        protected void TriggerError(FormEvent e)
        {
            if (Config.DebugMode)
                if (OnError != null)
                    OnError(this, e);
        }

        protected void TriggerGetCount(FormEvent e)
        {
            if (OnGetCount != null)
                OnGetCount(this, e);
        }

        protected void TriggerGetActive(FormEvent e)
        {
            if (OnGetActive != null)
                OnGetActive(this, e);
        }

        protected void TriggerGetById(FormEvent e)
        {
            if (OnGetById != null)
                OnGetById(this, e);
        }

        protected void TriggerGetId(FormEvent e)
        {
            if (OnGetId != null)
                OnGetId(this, e);
        }
        #endregion

        #region BackGroundWorker Members
        protected virtual void BgwFetchDoWork(object sender, DoWorkEventArgs e) { }

        protected virtual void BgFetchRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { }

        protected virtual void BgwFetchListsDoWork(object sender, DoWorkEventArgs e) { }

        protected virtual void BgFetchListsRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            TriggerFetchLists(new FormEvent(!IsError) { Value = e.Result });
            IsError = false;
        }

        protected virtual void BgwInsertDoWork(object sender, DoWorkEventArgs e) { }

        protected virtual void BgInsertRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var a = (DataRow)e.Result;
            var id = ToUInt64(a["id"]);
            TriggerInsert(new FormEvent(!id.Equals("0") && !IsError)
            {
                Value = a,
                Exception = new Exception(id.Equals(0) ? "Insert failed." : "Insert success.")
            });
            IsError = false;
        }

        protected virtual void BgwUpdateDoWork(object sender, DoWorkEventArgs e) { }

        protected virtual void BgUpdateRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            TriggerUpdate(new FormEvent(IsSuccess)
            {
                Value = e.Result,
                Exception = new Exception(!IsSuccess ? "Update failed." : "Update success.")
            });
        }

        protected virtual void BgwDeleteDoWork(object sender, DoWorkEventArgs e) { }

        protected virtual void BgDeleteRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            TriggerDelete(new FormEvent(IsSuccess && !IsError)
                              {
                                  Value = e.Result,
                                  Exception = new Exception(!IsSuccess ? "Update failed." : "Update success.")
                              });
            IsError = false;
        }

        protected virtual void BgwToggleDoWork(object sender, DoWorkEventArgs e) { }

        protected virtual void BgToggleRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { }

        protected virtual void BgwGetCountDoWork(object sender, DoWorkEventArgs e) { }

        protected virtual void BgwGetCountWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            TriggerGetCount(new FormEvent(!IsError) { Value = e.Result });
            IsError = false;
        }

        protected virtual void BgwGetActiveDoWork(object sender, DoWorkEventArgs e) { }

        protected virtual void BgwGetActiveWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            TriggerGetActive(new FormEvent(!IsError) { Value = e.Result });
            IsError = false;
        }

        protected virtual void BgwGetByIdDoWork(object sender, DoWorkEventArgs e) { }

        protected virtual void BgwGetByIdWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { }

        protected virtual void BgwGetIdDoWork(object sender, DoWorkEventArgs e) { }

        protected virtual void BgwGetIdWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { }
        #endregion

        #region Members
        public virtual void Fetch()
        {
            using (var a = new BackgroundWorker())
            {
                a.DoWork += BgwFetchDoWork;
                a.RunWorkerCompleted += BgFetchRunWorkerCompleted;
                a.RunWorkerAsync();
            }
        }

        public virtual void Fetch(object data)
        {
            using (var a = new BackgroundWorker())
            {
                a.DoWork += BgwFetchDoWork;
                a.RunWorkerCompleted += BgFetchRunWorkerCompleted;
                a.RunWorkerAsync(data);
            }
        }

        public virtual void FetchLists()
        {
            using (var a = new BackgroundWorker())
            {
                a.DoWork += BgwFetchListsDoWork;
                a.RunWorkerCompleted += BgFetchListsRunWorkerCompleted;
                a.RunWorkerAsync();
            }
        }

        public virtual void FetchLists(object data)
        {
            using (var a = new BackgroundWorker())
            {
                a.DoWork += BgwFetchListsDoWork;
                a.RunWorkerCompleted += BgFetchListsRunWorkerCompleted;
                a.RunWorkerAsync(data);
            }
        }

        public virtual void Insert(DataRow data)
        {
            using (var a = new BackgroundWorker())
            {
                a.DoWork += BgwInsertDoWork;
                a.RunWorkerCompleted += BgInsertRunWorkerCompleted;
                a.RunWorkerAsync(data);
            }
        }

        public virtual void Update(DataRow data)
        {
            using (var a = new BackgroundWorker())
            {
                a.DoWork += BgwUpdateDoWork;
                a.RunWorkerCompleted += BgUpdateRunWorkerCompleted;
                a.RunWorkerAsync(data);
            }
        }

        public virtual void Delete(DataRow data)
        {
            using (var a = new BackgroundWorker())
            {
                a.DoWork += BgwDeleteDoWork;
                a.RunWorkerCompleted += BgDeleteRunWorkerCompleted;
                a.RunWorkerAsync(data);
            }
        }

        public virtual void Toggle(UInt64 id, bool active)
        {
            using (var a = new BackgroundWorker())
            {
                a.DoWork += BgwToggleDoWork;
                a.RunWorkerCompleted += BgToggleRunWorkerCompleted;
                a.RunWorkerAsync(new object[] { id, active });
            }
        }

        public virtual void GetCount()
        {
            using (var a = new BackgroundWorker())
            {
                a.DoWork += BgwGetCountDoWork;
                a.RunWorkerCompleted += BgwGetCountWorkerCompleted;
                a.RunWorkerAsync();
            }
        }

        public virtual void GetActive()
        {
            using (var a = new BackgroundWorker())
            {
                a.DoWork += BgwGetActiveDoWork;
                a.RunWorkerCompleted += BgwGetActiveWorkerCompleted;
                a.RunWorkerAsync();
            }
        }

        public void GetById(UInt64 id)
        {
            using (var a = new BackgroundWorker())
            {
                a.DoWork += BgwGetByIdDoWork;
                a.RunWorkerCompleted += BgwGetByIdWorkerCompleted;
                a.RunWorkerAsync(id);
            }
        }

        public void GetIdByParams(params object[] data)
        {
            using (var a = new BackgroundWorker())
            {
                a.DoWork += BgwGetIdDoWork;
                a.RunWorkerCompleted += BgwGetIdWorkerCompleted;
                a.RunWorkerAsync(data);
            }
        }

        protected UInt64 ToUInt64(object data)
        {
            try { return Convert.ToUInt64(data); }
            catch (Exception) { return 0; }
        }

        protected UInt64 ToUInt32(object data)
        {
            try { return Convert.ToUInt32(data); }
            catch (Exception) { return 0; }
        }

        protected UInt64 ToUInt16(object data)
        {
            try { return Convert.ToUInt16(data); }
            catch (Exception) { return 0; }
        }
        #endregion
    }
}